/*
 * MIT License
 *
 * Copyright (c) 2023 北京凯特伟业科技有限公司
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.je.workflow.service.model;

import cn.hutool.core.io.FileUtil;
import com.google.common.base.Charsets;
import com.google.common.base.Strings;
import com.je.bpm.core.model.BpmnModel;
import com.je.bpm.core.model.FlowElement;
import com.je.bpm.core.model.FlowNode;
import com.je.bpm.core.model.SequenceFlow;
import com.je.bpm.core.model.config.ProcessDeployTypeEnum;
import com.je.bpm.core.model.event.EndEvent;
import com.je.bpm.core.model.gateway.InclusiveGateway;
import com.je.bpm.core.model.task.KaiteBaseUserTask;
import com.je.bpm.engine.*;
import com.je.bpm.engine.history.HistoricActivityInstance;
import com.je.bpm.engine.history.HistoricProcessInstance;
import com.je.bpm.engine.repository.ProcessDefinition;
import com.je.bpm.engine.task.Comment;
import com.je.bpm.engine.task.Task;
import com.je.bpm.model.process.ModelOperatorService;
import com.je.bpm.runtime.shared.RemoteCallServeManager;
import com.je.common.base.DynaBean;
import com.je.common.base.mapper.query.NativeQuery;
import com.je.common.base.service.MetaResourceService;
import com.je.common.base.service.MetaService;
import com.je.common.base.workflow.vo.OperationTypeEnum;
import com.je.ibatis.extension.conditions.ConditionsWrapper;
import com.je.workflow.service.usertask.impl.RemoteCallServeManagerImpl;
import com.mxgraph.io.mxCodec;
import com.mxgraph.model.mxCell;
import com.mxgraph.model.mxICell;
import com.mxgraph.util.*;
import com.mxgraph.view.mxGraph;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.w3c.dom.Document;

import javax.imageio.ImageIO;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.*;

@Service
public class ModelServiceImpl implements ModelService {

    private static final Logger logger = LoggerFactory.getLogger(ModelServiceImpl.class);

    @Autowired
    private MetaService metaService;
    @Autowired
    private ModelOperatorService modelOperatorService;
    @Autowired
    private Environment environment;
    @Autowired
    private HistoryService historyService;
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private RemoteCallServeManager remoteCallServeManager;
    @Autowired
    MetaResourceService metaResourceService;


    private static final String TABLE_CODE = "JE_WORKFLOW_PROCESSINFO";

    @Override
    public File generateImage(String beanId, String pdid) {
        String directory = environment.getProperty("servicecomb.downloads.directory") + File.separator + "workflow";
        if (!FileUtil.exist(directory)) {
            FileUtil.mkdir(directory);
        }
        //当前运行节点
        List<String> randingIds = new ArrayList<>();
        //历史流转节点
        List<String> endingIds = new ArrayList<>();
        //历史流转节点时间排序的
        List<String> endingIdsTimeAscList = new ArrayList<>();
        //异常节点,退回，取回，驳回的节点
        List<String> abnormalNodes = new ArrayList<>();
        if (!Strings.isNullOrEmpty(beanId)) {
            pdid = buildProcessNodesInfos(beanId, randingIds, endingIds, pdid, endingIdsTimeAscList, abnormalNodes);
        }
        String pngName = UUID.randomUUID().toString();
        String imageFile = directory + File.separator + pngName + ".xml";
        byte[] xmlBytes = getXmlBytesByPdid(pdid);
        try {
            mxGraph graph = new mxGraph();
            String xml = new String(xmlBytes, Charsets.UTF_8);
            xml = URLDecoder.decode(xml);
            Document doc = mxXmlUtils.parseXml(mxUtils.readInputStream(new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8))));
            mxCodec codec = new mxCodec(doc);
            codec.decode(doc.getDocumentElement(), graph.getModel());
            //获取root节点
            recursiveSetNodeValue((mxCell) graph.getModel().getRoot(), randingIds, endingIds, endingIdsTimeAscList, abnormalNodes);
            Document svgDocument = mxCellRenderer.createSvgDocument(graph, null, 1, null, null);
            File file = new File(imageFile);
            // 将 Document 转换为 DOMSource
            DOMSource source = new DOMSource(svgDocument);
            // 创建输出文件路径
            // 创建输出文件的 StreamResult
            StreamResult result = new StreamResult(file);
            // 创建 TransformerFactory
            TransformerFactory transformerFactory = TransformerFactory.newInstance();
            // 执行转换并将 Document 写入文件
            Transformer transformer = transformerFactory.newTransformer();
            transformer.transform(source, result);
            return file;
        } catch (IOException | TransformerConfigurationException e) {
            e.printStackTrace();
        } catch (TransformerException e) {
            e.printStackTrace();
        }
        return null;
    }


    private String buildProcessNodesInfos(String beanId, List<String> randingIds, List<String> endingIds, String pdid, List<String> endingIdsTimeAscList,
                                          List<String> abnormalNodes) {
        List<HistoricProcessInstance> procinst = historyService.createHistoricProcessInstanceQuery().processInstanceBusinessKey(beanId).list();
        if (procinst.size() == 0) {
            return pdid;
        }
        String piid = procinst.get(0).getId();
        pdid = procinst.get(0).getProcessDefinitionId();
        Map<String, Date> actinstMap = new HashMap<>();
        List<HistoricActivityInstance> actinst = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(piid).orderByHistoricActivityInstanceStartTime().asc().list();
        if (actinst.size() == 0) {
            return pdid;
        }
        String lastHistTaskNodeId = "";
        for (HistoricActivityInstance historicActivityInstance : actinst) {
            endingIdsTimeAscList.add(historicActivityInstance.getActivityId());
            actinstMap.put(historicActivityInstance.getActivityId(), historicActivityInstance.getStartTime());
            lastHistTaskNodeId = historicActivityInstance.getActivityId();
            if (lastHistTaskNodeId.startsWith("end")) {
                endingIds.add(lastHistTaskNodeId);
            }
        }
        abnormalNodes.addAll(buildAbnormalNodes(actinst, piid));
        BpmnModel bpmnModel = repositoryService.getBpmnModel(pdid);

        List<Task> randingTask = taskService.createTaskQuery().processInstanceId(piid).list();
        for (Task task : randingTask) {
            randingIds.add(task.getTaskDefinitionKey());
        }
        for (Task task : randingTask) {
            FlowElement flowElement = bpmnModel.getFlowElement(task.getTaskDefinitionKey());
            findBeforeRandingNodeIds(bpmnModel, flowElement, endingIds, actinstMap, randingIds, abnormalNodes);
        }

        if (randingTask.size() == 0) {
            FlowElement flowElement = bpmnModel.getFlowElement(lastHistTaskNodeId);
            endingIds.add(lastHistTaskNodeId);
            findBeforeRandingNodeIds(bpmnModel, flowElement, endingIds, actinstMap, randingIds, abnormalNodes);
        }

        return pdid;
    }


    private List<String> buildAbnormalNodes(List<HistoricActivityInstance> actinst, String piid) {
        List<String> resultMap = new ArrayList<>();
        Map<String, Comment> commentMap = new HashMap<>();
        List<Comment> comments = taskService.getProcessInstanceComments(piid, "node");
        for (Comment comment : comments) {
            commentMap.put(comment.getTaskId(), comment);
        }
        for (HistoricActivityInstance historicActivityInstance : actinst) {
            resultMap.remove(historicActivityInstance.getActivityId());
            if (commentMap.get(historicActivityInstance.getTaskId()) == null) {
                continue;
            }
            OperationTypeEnum operationTypeEnum =
                    OperationTypeEnum.getTypeByName(commentMap.get(historicActivityInstance.getTaskId()).getFullMessage());
            if (operationTypeEnum == OperationTypeEnum.DISMISS || operationTypeEnum == OperationTypeEnum.GO_BACK ||
                    operationTypeEnum == OperationTypeEnum.RETRIEVE) {
                resultMap.add(historicActivityInstance.getActivityId());
            }
        }
        return resultMap;
    }

    private void findBeforeRandingNodeIds(BpmnModel bpmnModel, FlowElement flowElement, List<String> endingIds, Map<String, Date> actinstMap,
                                          List<String> randingIds, List<String> abnormalNodes) {
        if (flowElement instanceof KaiteBaseUserTask || flowElement instanceof EndEvent) {
            buildKaiteBaseUserTaskHistEndingNode((FlowNode) flowElement, endingIds, bpmnModel, actinstMap, randingIds, abnormalNodes);
        }
        if (flowElement instanceof InclusiveGateway) {
            //往前找
            buildForwardGateWayTaskHistEndingNode(flowElement, endingIds, bpmnModel, actinstMap, randingIds, abnormalNodes);
            //往后找
            if (randingIds.size() > 0) {
                buildBackGateWayTaskHistEndingNode(flowElement, endingIds, bpmnModel, actinstMap, randingIds, abnormalNodes);
            }
        }
    }

    private void buildBackGateWayTaskHistEndingNode(FlowElement flowElement, List<String> endingIds, BpmnModel bpmnModel,
                                                    Map<String, Date> actinstMap, List<String> randingIds, List<String> abnormalNodes) {
        FlowNode flowNode = (FlowNode) flowElement;
        List<SequenceFlow> sequenceFlowList = flowNode.getOutgoingFlows();
        for (SequenceFlow sequenceFlow : sequenceFlowList) {
            if (actinstMap.get(sequenceFlow.getSourceRef()) == null) {
                continue;
            }
            if (randingIds.contains(sequenceFlow.getTargetRef())) {
                continue;
            }
            endingIds.add(sequenceFlow.getSourceRef());
            flowElement = bpmnModel.getFlowElement(sequenceFlow.getTargetRef());
            buildBackGateWayTaskHistEndingNode(flowElement, endingIds, bpmnModel, actinstMap, randingIds, abnormalNodes);
        }
    }

    private void buildForwardGateWayTaskHistEndingNode(FlowElement flowElement, List<String> endingIds, BpmnModel bpmnModel,
                                                       Map<String, Date> actinstMap, List<String> randingIds, List<String> abnormalNodes) {
        InclusiveGateway inclusiveGateway = (InclusiveGateway) flowElement;
        List<SequenceFlow> sequenceFlowList = inclusiveGateway.getIncomingFlows();
        if (sequenceFlowList.size() == 0) {
            return;
        }
        if (sequenceFlowList.size() == 1) {
            String sourceNodeId = sequenceFlowList.get(0).getSourceRef();
            if (endingIds.contains(sourceNodeId)) {
                return;
            }
            endingIds.add(sourceNodeId);
            flowElement = bpmnModel.getFlowElement(sourceNodeId);
            findBeforeRandingNodeIds(bpmnModel, flowElement, endingIds, actinstMap, randingIds, abnormalNodes);
        }

        if (sequenceFlowList.size() > 1) {
            for (SequenceFlow sequenceFlow : sequenceFlowList) {
                if (actinstMap.get(sequenceFlow.getSourceRef()) == null) {
                    continue;
                }
                endingIds.add(sequenceFlow.getSourceRef());
                flowElement = bpmnModel.getFlowElement(sequenceFlow.getSourceRef());
                findBeforeRandingNodeIds(bpmnModel, flowElement, endingIds, actinstMap, randingIds, abnormalNodes);
            }
        }
    }

    private void buildKaiteBaseUserTaskHistEndingNode(FlowNode flowNode, List<String> endingIds, BpmnModel bpmnModel,
                                                      Map<String, Date> actinstMap, List<String> randingIds, List<String> abnormalNodes) {
        List<SequenceFlow> sequenceFlowList = flowNode.getIncomingFlows();
        if (sequenceFlowList.size() == 0) {
            return;
        }

        if (sequenceFlowList.size() == 1) {
            String sourceNodeId = sequenceFlowList.get(0).getSourceRef();
            if (endingIds.contains(sourceNodeId)) {
                return;
            }
            endingIds.add(sourceNodeId);
            flowNode = (FlowNode) bpmnModel.getFlowElement(sourceNodeId);
            findBeforeRandingNodeIds(bpmnModel, flowNode, endingIds, actinstMap, randingIds, abnormalNodes);
        }
        List<String> lastNodeIds = new ArrayList<>();
        if (sequenceFlowList.size() > 1) {
            for (SequenceFlow sequenceFlow : sequenceFlowList) {
                String sourceRefId = sequenceFlow.getSourceRef();
                if (!randingIds.contains(sourceRefId) && abnormalNodes.contains(sourceRefId)) {
                    continue;
                }
                if (actinstMap.get(sourceRefId) != null) {
                    lastNodeIds.add(sourceRefId);
                }
            }
        }

        for (String lastNodeId : lastNodeIds) {
            if (endingIds.contains(lastNodeId)) {
                return;
            }
            endingIds.add(lastNodeId);
            flowNode = (FlowNode) bpmnModel.getFlowElement(lastNodeId);
            findBeforeRandingNodeIds(bpmnModel, flowNode, endingIds, actinstMap, randingIds, abnormalNodes);
        }

    }


    private byte[] getXmlBytesByPdid(String pdid) {
        List<DynaBean> dynaBeans = metaService.select("act_ge_bytearray", ConditionsWrapper.builder().eq("NAMESPACE_", pdid));
        if (dynaBeans != null) {
            Object bytes = dynaBeans.get(0).get("BYTES_");
            if (bytes == null) {
                return null;
            }
            return (byte[]) bytes;
        }
        return null;
    }

    private void recursiveSetNodeValue(mxCell cell, List<String> randingIds, List<String> endingIds, List<String> endingIdsTimeAscList, List<String> abnormalNodes) {
        int count = cell.getChildCount();
        if (count <= 0) {
            return;
        }
        mxCell eachCell;
        String imageStyle = "";
        for (int i = 0; i < count; i++) {
            imageStyle = "";
            eachCell = (mxCell) cell.getChildAt(i);
            if (!eachCell.getId().startsWith("line")) {
                if (!Strings.isNullOrEmpty(eachCell.getAttribute("label"))) {
                    eachCell.setValue(eachCell.getAttribute("label"));
                } else {
                    eachCell.setValue(null);
                }
            }

            if (eachCell.getId().startsWith("start")) {
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_SHAPE, mxConstants.STYLE_IMAGE);
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_IMAGE, NodeTypeEnum.START.getBase64());
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_SPACING_BOTTOM, "-35");
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_FONTCOLOR, "#130c0e");
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_FONTSIZE, "13");

            }
            if (eachCell.getId().startsWith("end")) {
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_SHAPE, mxConstants.STYLE_IMAGE);
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_IMAGE, NodeTypeEnum.END.getBase64());
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_SPACING_BOTTOM, "-35");
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_FONTCOLOR, "#130c0e");
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_FONTSIZE, "13");
            }
            if (eachCell.getId().startsWith("decision")) {
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_SHAPE, mxConstants.STYLE_IMAGE);
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_IMAGE, NodeTypeEnum.JUDGE.getBase64());
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_SPACING_BOTTOM, "-35");
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_FONTCOLOR, "#130c0e");
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_FONTSIZE, "13");
            }
            if (eachCell.getId().startsWith("branchGateway")) {
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_SHAPE, mxConstants.STYLE_IMAGE);
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_IMAGE, NodeTypeEnum.BRANCH.getBase64());
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_SPACING_BOTTOM, "-35");
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_FONTCOLOR, "#130c0e");
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_FONTSIZE, "13");
            }
            if (eachCell.getId().startsWith("aggregationGateway")) {
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_SHAPE, mxConstants.STYLE_IMAGE);
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_IMAGE, NodeTypeEnum.AGGREGATE.getBase64());
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_SPACING_BOTTOM, "-35");
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_FONTCOLOR, "#130c0e");
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_FONTSIZE, "13");
            }
            if (eachCell.getId().startsWith("countersign")) {
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_SHAPE, mxConstants.STYLE_IMAGE);
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_IMAGE, NodeTypeEnum.COUNTER_SIGN.getBase64());
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_SPACING_BOTTOM, "-35");
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_FONTCOLOR, "#130c0e");
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_FONTSIZE, "13");
            }
            if (eachCell.getId().startsWith("random")) {
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_SHAPE, mxConstants.STYLE_IMAGE);
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_IMAGE, NodeTypeEnum.RANDOM_TASK.getBase64());
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_SPACING_BOTTOM, "-35");
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_FONTCOLOR, "#130c0e");
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_FONTSIZE, "13");
            }
            if (eachCell.getId().startsWith("to_assignee")) {
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_SHAPE, mxConstants.STYLE_IMAGE);
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_IMAGE, NodeTypeEnum.FIX.getBase64());
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_SPACING_BOTTOM, "-35");
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_FONTCOLOR, "#130c0e");
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_FONTSIZE, "13");
            }
            if (eachCell.getId().startsWith("joint")) {
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_SHAPE, mxConstants.STYLE_IMAGE);
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_IMAGE, NodeTypeEnum.CANDIDATE.getBase64());
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_SPACING_BOTTOM, "-35");
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_FONTCOLOR, "#130c0e");
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_FONTSIZE, "13");
            }
            if (eachCell.getId().startsWith("circular")) {
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_SHAPE, mxConstants.STYLE_IMAGE);
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_IMAGE, NodeTypeEnum.FREEDOM.getBase64());
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_SPACING_BOTTOM, "-35");
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_FONTCOLOR, "#130c0e");
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_FONTSIZE, "13");
            }
            if (eachCell.getId().startsWith("batchtask")) {
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_SHAPE, mxConstants.STYLE_IMAGE);
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_IMAGE, NodeTypeEnum.MULTI_TASK.getBase64());
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_SPACING_BOTTOM, "-35");
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_FONTCOLOR, "#130c0e");
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_FONTSIZE, "13");
            }

            if (eachCell.getId().startsWith("task")) {
                imageStyle = eachCell.getStyle();
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_LABEL_POSITION, "ALIGN_CENTER");
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_VERTICAL_LABEL_POSITION, "ALIGN_MIDDLE");
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_SPACING_BOTTOM, "-2");
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_FONTCOLOR, "#130c0e");
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_FONTSIZE, "13");
            }

            if (eachCell.getId().startsWith("line")) {
                Boolean isGreen = false;
                imageStyle = eachCell.getStyle();
                if (!imageStyle.contains(mxConstants.STYLE_STROKECOLOR)) {
                    imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_STROKECOLOR, "#130c0e");
                }
                if (eachCell.getTarget() != null) {
                    if (endingIds.contains(eachCell.getTarget().getId()) || randingIds.contains(eachCell.getTarget().getId())) {
                        //1. 查询线的targetNode有几个入线，如果存在1个，直接点亮
                        //2.如果存在两个以上，需要找寻target节点的sourceNode，然后获取历史节点，查询最后一次执行的sourceNode节点
                        //3.判断当前的line是否是需要点亮的line，判断的依据是sourceNode和targetNode连接的line点亮即可
                        List<mxCell> sourceNodes = new ArrayList<>();
                        String targetId = eachCell.getTarget().getId();
                        if (eachCell.getTarget().getEdgeCount() > 1) {
                            for (int j = 0; j < eachCell.getTarget().getEdgeCount(); j++) {
                                mxICell mxICell = eachCell.getTarget().getEdgeAt(j);
                                if (mxICell instanceof mxCell) {
                                    mxCell mxCell = (com.mxgraph.model.mxCell) mxICell;
                                    if (mxCell.getTarget().getId().equals(eachCell.getTarget().getId())) {
                                        sourceNodes.add((com.mxgraph.model.mxCell) mxCell.getSource());
                                    }
                                }
                            }
                        }
                        if (sourceNodes.size() == 1) {
                            isGreen = true;
                        } else {
                            String[] mxCellIds = new String[sourceNodes.size()];
                            String firstId = "";
                            for (int q = 0; q < mxCellIds.length; q++) {
                                mxCellIds[q] = sourceNodes.get(q).getId();
                            }

                            List<String> idSet = new ArrayList<>(Arrays.asList(mxCellIds));
                            for (String item : endingIdsTimeAscList) {
                                if (idSet.contains(item)) {
                                    firstId = item;
                                }
                            }
                            for (mxCell mxCell : sourceNodes) {
                                if (mxCell.getId().equals(firstId)) {
                                    //如果线的入节点是当前节点，出点是结束节点，点亮
                                    for (int k = 0; k < mxCell.getEdgeCount(); k++) {
                                        mxCell mxCell1 = (com.mxgraph.model.mxCell) mxCell.getEdgeAt(k);
                                        if (mxCell1.getId().equals(eachCell.getId())) {
                                            if (mxCell1.getTarget().getId().equals(targetId) && mxCell1.getSource().getId().equals(firstId)) {
                                                if (!abnormalNodes.contains(mxCell1.getSource().getId())) {
                                                    isGreen = true;
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }

                        if (isGreen == false) {
                            String target = eachCell.getTarget().getId();
                            String source = eachCell.getSource().getId();
                            if (!abnormalNodes.contains(source)) {
                                for (int p = 1; p < endingIdsTimeAscList.size(); p++) {
                                    if (endingIdsTimeAscList.get(p).equals(target)) {
                                        if (endingIdsTimeAscList.get(p - 1).equals(source)) {
                                            isGreen = true;
                                            break;
                                        }
                                    }
                                }
                            }
                        }

                        if (isGreen == false) {
                            String target = eachCell.getTarget().getId();
                            String source = eachCell.getSource().getId();
                            if (target.startsWith("aggregationGateway") && endingIds.contains(target) && endingIds.contains(source)
                                    && !abnormalNodes.contains(source) && !randingIds.contains(source)) {
                                isGreen = true;
                            }
                        }

                    }
                    if (isGreen) {
                        imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_STROKECOLOR, StyleStrokeColorEnum.GREEN.getValue());
                        imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_STROKEWIDTH, "2");
                    }

                }
                //如果线连接的是结束节点，并且结束节点存在在历史节点中，则点亮线绿色
//                if (eachCell.getSource().getId().startsWith("end") && endingIds.contains(eachCell.getSource().getId())) {
//                    imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_STROKECOLOR, StyleStrokeColorEnum.GREEN.getValue());
//                    imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_STROKEWIDTH, "2");
//                }
                //设置字体颜色
                if (!imageStyle.contains(mxConstants.STYLE_FONTCOLOR)) {
                    imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_FONTCOLOR, "#130c0e");
                }
                //设置字体大小
                if (!imageStyle.contains(mxConstants.STYLE_FONTSIZE)) {
                    imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_FONTSIZE, "13");
                }
            }
            //设置节点样式
            imageStyle = setRindingStyle(eachCell.getId(), randingIds, endingIds, imageStyle);
            if (!Strings.isNullOrEmpty(imageStyle)) {
                eachCell.setStyle(imageStyle);
            }
            recursiveSetNodeValue(eachCell, randingIds, endingIds, endingIdsTimeAscList, abnormalNodes);
        }
    }

    public String setRindingStyle(String id, List<String> randingIds, List<String> endingIds, String imageStyle) {
        String type = getRunState(id, randingIds, endingIds);
        if (type == null) {
            if (id.startsWith("decision")) {
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_IMAGE, NodeTypeEnum.JUDGE.getBase64());
            }
            if (id.startsWith("branchGateway")) {
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_IMAGE, NodeTypeEnum.BRANCH.getBase64());
            }
            if (id.startsWith("aggregationGateway")) {
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_IMAGE, NodeTypeEnum.AGGREGATE.getBase64());
            }
            if (id.startsWith("countersign")) {
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_IMAGE, NodeTypeEnum.COUNTER_SIGN.getBase64());
            }
            if (id.startsWith("to_assignee")) {
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_IMAGE, NodeTypeEnum.FIX.getBase64());
            }
            if (id.startsWith("joint")) {
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_IMAGE, NodeTypeEnum.CANDIDATE.getBase64());
            }
            if (id.startsWith("circular")) {
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_IMAGE, NodeTypeEnum.FREEDOM.getBase64());
            }
            if (id.startsWith("batchtask")) {
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_IMAGE, NodeTypeEnum.MULTI_TASK.getBase64());
            }
            if (id.startsWith("random")) {
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_IMAGE, NodeTypeEnum.RANDOM_TASK.getBase64());
            }
            return imageStyle;
        }

        if (type.equals("run")) {
            if (id.startsWith("decision")) {
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_IMAGE, NodeTypeEnum.JUDGE_RUN.getBase64());
            }
            if (id.startsWith("branchGateway")) {
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_IMAGE, NodeTypeEnum.BRANCH_RUN.getBase64());
            }
            if (id.startsWith("aggregationGateway")) {
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_IMAGE, NodeTypeEnum.AGGREGATE_RUN.getBase64());
            }
            if (id.startsWith("countersign")) {
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_IMAGE, NodeTypeEnum.COUNTER_SIGN_RUN.getBase64());
            }
            if (id.startsWith("to_assignee")) {
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_IMAGE, NodeTypeEnum.FIX_RUN.getBase64());
            }
            if (id.startsWith("joint")) {
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_IMAGE, NodeTypeEnum.CANDIDATE_RUN.getBase64());
            }
            if (id.startsWith("circular")) {
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_IMAGE, NodeTypeEnum.FREEDOM_RUN.getBase64());
            }
            if (id.startsWith("batchtask")) {
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_IMAGE, NodeTypeEnum.MULTI_TASK_RUN.getBase64());
            }
            if (id.startsWith("random")) {
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_IMAGE, NodeTypeEnum.RANDOM_TASK_RUN.getBase64());
            }

            if (id.startsWith("task")) {
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_STROKECOLOR, StyleStrokeColorEnum.RED.getValue());
                //底色
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_FILLCOLOR, StyleStrokeColorEnum.WHITE.getValue());
                //圆角
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_ROUNDED, "true");
                //边框宽度
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_STROKEWIDTH, "3");
            }

        }

        if (type.equals("end")) {
            if (id.startsWith("decision")) {
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_IMAGE, NodeTypeEnum.JUDGE_END.getBase64());
            }
            if (id.startsWith("branchGateway")) {
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_IMAGE, NodeTypeEnum.BRANCH_END.getBase64());
            }
            if (id.startsWith("aggregationGateway")) {
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_IMAGE, NodeTypeEnum.AGGREGATE_END.getBase64());
            }
            if (id.startsWith("countersign")) {
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_IMAGE, NodeTypeEnum.COUNTER_SIGN_END.getBase64());
            }
            if (id.startsWith("to_assignee")) {
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_IMAGE, NodeTypeEnum.FIX_END.getBase64());
            }
            if (id.startsWith("joint")) {
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_IMAGE, NodeTypeEnum.CANDIDATE_END.getBase64());
            }
            if (id.startsWith("circular")) {
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_IMAGE, NodeTypeEnum.FREEDOM_END.getBase64());
            }
            if (id.startsWith("batchtask")) {
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_IMAGE, NodeTypeEnum.MULTI_TASK_END.getBase64());
            }
            if (id.startsWith("random")) {
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_IMAGE, NodeTypeEnum.RANDOM_TASK_END.getBase64());
            }

            if (id.startsWith("task")) {
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_STROKECOLOR, StyleStrokeColorEnum.GREEN.getValue());
                //底色
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_FILLCOLOR, StyleStrokeColorEnum.WHITE.getValue());
                //圆角
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_ROUNDED, "true");
                //边框宽度
                imageStyle = mxStyleUtils.setStyle(imageStyle, mxConstants.STYLE_STROKEWIDTH, "3");
            }

        }

        return imageStyle;
    }

    private String getRunState(String id, List<String> randingIds, List<String> endingIds) {
        if (randingIds.contains(id)) {
            return "run";
        } else if (endingIds.contains(id)) {
            return "end";
        } else {
            return null;
        }
    }


    @Override
    public List<Map<String, String>> getProcessPlanningList(String funcCode, String beanId) {
        List<Map<String, String>> list = new ArrayList<>();
        List<HistoricProcessInstance> procinst = historyService.createHistoricProcessInstanceQuery().
                processInstanceBusinessKey(beanId).list();
        if (procinst.size() == 0) {
            List<DynaBean> dynaBeans = metaService.select("JE_WORKFLOW_PROCESSINFO", ConditionsWrapper.builder().
                    eq("PROCESSINFO_FUNC_CODE", funcCode).eq("PROCESSINFO_DEPLOY", "1"));
            for (DynaBean dynaBean : dynaBeans) {
                Map<String, String> map = new HashMap<>();
                map.put("name", dynaBean.getStr("PROCESSINFO_NAME"));
                List<ProcessDefinition> processDefinitions = repositoryService.createProcessDefinitionQuery().
                        processDefinitionKey(dynaBean.getStr("PROCESSINFO_KEY")).latestVersion().list();
                String pdid = processDefinitions.get(0).getId();
                DynaBean metaInfoXMl = metaService.selectOne("act_ge_bytearray",
                        ConditionsWrapper.builder().eq("NAMESPACE_", pdid));
                map.put("xmlId", metaInfoXMl.getStr("ID_"));
                list.add(map);
            }
        } else {
            Map<String, String> map = new HashMap<>();
            String pdid = procinst.get(0).getProcessDefinitionId();
            DynaBean metaInfoXMl = metaService.selectOne("act_ge_bytearray",
                    ConditionsWrapper.builder().eq("NAMESPACE_", pdid));
            map.put("xmlId", metaInfoXMl.getStr("ID_"));
            map.put("name", procinst.get(0).getProcessDefinitionName());
            list.add(map);
        }
        return list;
    }

    @Override
    public String doSave(DynaBean dynaBean, String metaInfoJson, String metaInfoXml) {
        dynaBean.set("PROCESSINFO_VERSION", "1");
        dynaBean.set("PROCESSINFO_DEPLOY", "0");
        dynaBean.set("PROCESSINFO_DEPLOYMENT_ENVIRONMENT", ProcessDeployTypeEnum.DEVELOP.toString());
        String modelId = modelOperatorService.saveModel("", metaInfoJson, dynaBean.getStr("PROCESSINFO_FUNC_CODE")).getEntity().getId();
        dynaBean.setStr("PROCESSINFO_MODEL_ID", modelId);
        logger.info("升级开始。。。。。。。。。。。。。。");
        if (Strings.isNullOrEmpty(dynaBean.getStr("PROCESSINFO_RESOURCE_XML_ID"))) {
            logger.info("PROCESSINFO_RESOURCE_XML_ID为空。。。。。。。。。。。。。。");
            dynaBean.setStr("PROCESSINFO_RESOURCE_XML_ID", saveXmlInfo(metaInfoXml));
        } else {
            logger.info("PROCESSINFO_RESOURCE_XML_ID不为空,{}。。。。。。。。。。。。。。", dynaBean.getStr("PROCESSINFO_RESOURCE_XML_ID"));
            dynaBean.setStr("PROCESSINFO_RESOURCE_XML_ID", updateXmlInfo(dynaBean.getStr("PROCESSINFO_RESOURCE_XML_ID"), metaInfoXml, dynaBean));
        }
        return modelId;
    }

    private String saveXmlInfo(String metaInfoXml) {
        return saveXmlInfo(metaInfoXml, "");
    }

    private String saveXmlInfo(String metaInfoXml, String id) {
        DynaBean metaInfoXMl = new DynaBean("act_ge_bytearray", true);
        metaInfoXMl.set("REV_", 1);
        metaInfoXMl.set("NAME_", "xml");
        metaInfoXMl.set("BYTES_", metaInfoXml.getBytes());
        if (Strings.isNullOrEmpty(id)) {
            metaService.insert(metaInfoXMl);
            return metaInfoXMl.getPkValue();
        } else {
            metaInfoXMl.set("ID_", id);
            metaService.insert(metaInfoXMl);
            return id;
        }
    }

    @Override
    public String doUpdate(String modelId, String xmlId, DynaBean dynaBean, String metaInfoJson, String metaInfoXml) {
        String modeId = metaService.selectOneByPk(dynaBean.getTableCode(), dynaBean.getPkValue()).getStr("PROCESSINFO_MODEL_ID");
        xmlId = updateXmlInfo(xmlId, metaInfoXml, dynaBean);
        dynaBean.setStr("PROCESSINFO_RESOURCE_XML_ID", xmlId);
        return modelOperatorService.saveModel(modeId, metaInfoJson, dynaBean.getStr("PROCESSINFO_FUNC_CODE")).getEntity().getId();
    }

    private String updateXmlInfo(String xmlId, String metaInfoXml, DynaBean dynaBean) {
        logger.info("xmlId={}。。。。。。。。。。。。。。", xmlId);
        if (Strings.isNullOrEmpty(xmlId)) {
            DynaBean metaInfoXMl = new DynaBean("act_ge_bytearray", true);
            metaInfoXMl.set("REV_", 1);
            metaInfoXMl.set("NAME_", "xml");
            metaInfoXMl.set("BYTES_", metaInfoXml.getBytes());
            metaService.insert(metaInfoXMl);
            dynaBean.set("PROCESSINFO_RESOURCE_XML_ID", metaInfoXMl.getPkValue());
            return metaInfoXMl.getPkValue();
        } else {
            DynaBean metaInfoXMl = metaService.selectOne("act_ge_bytearray", ConditionsWrapper.builder().eq("ID_", xmlId));
            if (metaInfoXMl == null) {
                logger.info("selectOne==null。。。。。。。。。。。。。。");
                return saveXmlInfo(metaInfoXml, xmlId);
            } else {
                logger.info("selectOne!=null。。。。。。。。。。。。。。");
                metaInfoXMl.set("BYTES_", metaInfoXml.getBytes());
                metaService.update(metaInfoXMl);
                return metaInfoXMl.getPkValue();
            }
        }
    }

    @Override
    public void deploy(DynaBean dynaBean) {
        //设置版本号和部署状态
        String deployType = dynaBean.getStr("PROCESSINFO_DEPLOYMENT_ENVIRONMENT");
        if (Strings.isNullOrEmpty(deployType) || deployType.equals("YF")) {
            dynaBean.set("PROCESSINFO_VERSION", 1);
            clearHistProcessInfos(dynaBean.getStr("PROCESSINFO_KEY"));
            NativeQuery nativeQuery = new NativeQuery();
            nativeQuery.tableCode("JE_CORE_FUNCINFO");
            nativeQuery.eq("FUNCINFO_FUNCCODE", dynaBean.getStr("PROCESSINFO_FUNC_CODE"));
            List<DynaBean> list = metaResourceService.selectByNativeQuery(nativeQuery);
            if (list.size() > 0) {
                String tableCode = list.get(0).getStr("FUNCINFO_TABLENAME");
                clearUpcoming(dynaBean.getStr("PROCESSINFO_FUNC_ID"), tableCode, dynaBean.getStr("PROCESSINFO_KEY"));
                //清空审批告知
                clearApprovalNotice(dynaBean.getStr("PROCESSINFO_KEY"));
            }
            metaService.delete("ACT_GE_BYTEARRAY", ConditionsWrapper.builder().like("NAMESPACE_",
                    dynaBean.getStr("PROCESSINFO_KEY")));
        } else {
            dynaBean.setInt("PROCESSINFO_VERSION", dynaBean.getInt("PROCESSINFO_VERSION") + 1);
        }
        dynaBean.set("PROCESSINFO_DEPLOY", 1);

        if (Strings.isNullOrEmpty(dynaBean.getStr("PROCESSINFO_MODEL_ID"))) {
            throw new ActivitiException("流程modelId为空，部署失败！");
        }
        modelOperatorService.modelDeploy(dynaBean.getStr("PROCESSINFO_MODEL_ID"));

        String key = metaService.selectOneByPk("ACT_RE_MODEL", dynaBean.getStr("PROCESSINFO_MODEL_ID")).getStr("KEY_");
        dynaBean.setStr("PROCESSINFO_KEY", key);

        List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().
                processDefinitionKey(key).latestVersion().list();
        String pdid = list.get(0).getId();
        DynaBean metaInfoXMl = metaService.selectOne("act_ge_bytearray", ConditionsWrapper.builder().
                eq("ID_", dynaBean.getStr("PROCESSINFO_RESOURCE_XML_ID")));
        if (metaInfoXMl == null) {
            logger.info("deploy查询xml信息是否为null,,,{}", true);
        } else {
            logger.info("deploy查询xml信息是否为null,,,{}", false);
        }
        metaInfoXMl.setStr("ID_", UUID.randomUUID().toString());
        metaInfoXMl.setStr("NAMESPACE_", pdid);
        metaService.insert(metaInfoXMl);
        metaService.update(dynaBean);
    }

    @Override
    public void deploy(String processId) {
        DynaBean dynaBean = metaService.selectOneByPk(TABLE_CODE, processId);
        deploy(dynaBean);
    }

    //清空流程历史信息
    private void clearHistProcessInfos(String key) {
        if (Strings.isNullOrEmpty(key)) {
            return;
        }
        List<com.je.bpm.engine.repository.Deployment> list = repositoryService.createDeploymentQuery().deploymentKey(key).list();
        //1.根据部署对象ID删除流程定义
        for (com.je.bpm.engine.repository.Deployment deployment : list) {
            String deployId = deployment.getId();
            List<com.je.bpm.engine.repository.ProcessDefinition> processDefinitions = repositoryService.createProcessDefinitionQuery().
                    processDefinitionId(deployId).list();
            for (com.je.bpm.engine.repository.ProcessDefinition processDefinition : processDefinitions) {
                List<HistoricProcessInstance> histPiid = historyService.createHistoricProcessInstanceQuery().processDefinitionId(processDefinition.getId()).list();
                for (HistoricProcessInstance historicProcessInstance : histPiid) {
                    //2.删除历史流程实例根据流程实例ID
                    historyService.deleteHistoricProcessInstance(historicProcessInstance.getId());
                    //3.删除正在运行中的流程根据流程实例ID
                    runtimeService.deleteProcessInstance(historicProcessInstance.getId(), "", "", null);
                }
            }
            repositoryService.deleteDeployment(deployment.getId(), true);
        }
    }

    /**
     * 清空待办和业务数据的流程字段信息
     *
     * @param funcId
     * @param tableCode
     */
    private void clearUpcoming(String funcId, String tableCode, String key) {
        List<DynaBean> hiUpcoming = metaService.select("JE_WORKFLOW_HI_EXECUTION", ConditionsWrapper.builder().
                eq("EXECUTION_PROCESS_KEY", key));
        String prod = "";
        for (DynaBean dynaBean : hiUpcoming) {
            if (Strings.isNullOrEmpty(prod)) {
                prod = dynaBean.getStr("EXECUTION_PRODUCT_CODE");
            }
            metaService.delete("JE_WORKFLOW_HI_TASK", ConditionsWrapper.builder().eq("JE_WORKFLOW_HI_EXECUTION_ID", dynaBean.getPkValue()));
            metaService.delete("JE_WORKFLOW_HI_EXECUTION", ConditionsWrapper.builder().eq("JE_WORKFLOW_HI_EXECUTION_ID", dynaBean.getPkValue()));
        }

        List<DynaBean> randingUpcoming = metaService.select("JE_WORKFLOW_RN_EXECUTION", ConditionsWrapper.builder().
                eq("EXECUTION_PROCESS_KEY", key));

        for (DynaBean dynaBean : randingUpcoming) {
            if (Strings.isNullOrEmpty(prod)) {
                prod = dynaBean.getStr("EXECUTION_PRODUCT_CODE");
            }
            metaService.delete("JE_WORKFLOW_RN_TASK", ConditionsWrapper.builder().eq("JE_WORKFLOW_RN_EXECUTION_ID", dynaBean.getPkValue()));
            metaService.delete("JE_WORKFLOW_RN_EXECUTION", ConditionsWrapper.builder().eq("JE_WORKFLOW_RN_EXECUTION_ID", dynaBean.getPkValue()));
        }
        NativeQuery nativeQuery = NativeQuery.build();
        nativeQuery.tableCode("JE_CORE_FUNCINFO");
        nativeQuery.eq("JE_CORE_FUNCINFO_ID", funcId);
        List<DynaBean> list = metaResourceService.selectByNativeQuery(nativeQuery);
        if (list.size() > 0) {
            DynaBean dynaBean = list.get(0);
            String type = dynaBean.getStr("FUNCINFO_FUNCTYPE");
            if (type.equals(RemoteCallServeManagerImpl.FUNC_VIEW)) {
                tableCode = dynaBean.getStr("FUNCINFO_CRUDTABLENAME");
            }
        }
        remoteCallServeManager.clearBusinessDataWorkFlowFiledInfo(tableCode, prod, key);
    }

    /**
     * 清空审批告知
     *
     * @param processKey
     */
    private void clearApprovalNotice(String processKey) {
        metaService.delete("JE_WORKFLOW_APPROVALNOTICE", ConditionsWrapper.builder().eq("APPROVALNOTICE_PROCESSINFOKEY", processKey));
    }

    @Override
    @Transactional
    public void doRemove(String tableCode, String ids) {
        List<DynaBean> list = metaService.select(tableCode, ConditionsWrapper.builder().in("JE_WORKFLOW_PROCESSINFO_ID",
                ids.split(",")));
        for (DynaBean dynaBean : list) {
            if (dynaBean.getStr("PROCESSINFO_DEPLOY").equals("1")) {
                throw new ActivitiException(dynaBean.getStr("PROCESSINFO_NAME") + "未取消流程部署，不能删除！");
            }
        }
        for (DynaBean processInfo : list) {
            String modelId = processInfo.getStr("PROCESSINFO_MODEL_ID");
            clearHistProcessInfos(processInfo.getStr("PROCESSINFO_KEY"));
            NativeQuery nativeQuery = new NativeQuery();
            nativeQuery.tableCode("JE_CORE_FUNCINFO");
            nativeQuery.eq("FUNCINFO_FUNCCODE", processInfo.getStr("PROCESSINFO_FUNC_CODE"));
            List<DynaBean> businessData = metaResourceService.selectByNativeQuery(nativeQuery);
            if (businessData.size() > 0) {
                String table = businessData.get(0).getStr("FUNCINFO_TABLENAME");
                clearUpcoming(processInfo.getStr("PROCESSINFO_FUNC_ID"), table, processInfo.getStr("PROCESSINFO_KEY"));
                //清空审批告知
                clearApprovalNotice(processInfo.getStr("PROCESSINFO_KEY"));
            }
            metaService.delete("ACT_GE_BYTEARRAY", ConditionsWrapper.builder().like("NAMESPACE_",
                    processInfo.getStr("PROCESSINFO_KEY")));
            modelOperatorService.deleteModel(modelId);
        }
    }

    @Override
    public void unDeploy(String tableCode, String ids) {
        List<DynaBean> list = metaService.select(tableCode, ConditionsWrapper.builder().in("JE_WORKFLOW_PROCESSINFO_ID",
                ids.split(",")));
        for (DynaBean dynaBean : list) {
            if (dynaBean.getStr("PROCESSINFO_DEPLOY").equals("1")) {
                dynaBean.setStr("PROCESSINFO_DEPLOY", "0");
                metaService.update(dynaBean);
                metaService.executeSql(String.format("UPDATE act_re_model SET DEPLOY_STATUS_='0' WHERE ID_='%s'",
                        dynaBean.getStr("PROCESSINFO_MODEL_ID")));
            }
        }
    }

    @Override
    public void batchDeploy(String tableCode, String ids) {
        List<DynaBean> list = metaService.select(tableCode, ConditionsWrapper.builder().in("JE_WORKFLOW_PROCESSINFO_ID",
                ids.split(",")));
        for (DynaBean dynaBean : list) {
            deploy(dynaBean);
        }
    }

    @Override
    public String getJsonInfoById(String modelId) {
        if (Strings.isNullOrEmpty(modelId)) {
            return "";
        }
        return modelOperatorService.getModel(modelId).getEntity().getMetaInfo();
    }

    private byte[] getXmlBytesById(String xmlId) {
        DynaBean dynaBean = metaService.selectOneByPk("act_ge_bytearray", xmlId);
        if (dynaBean != null) {
            Object bytes = dynaBean.get("BYTES_");
            if (bytes == null) {
                return null;
            }
            return (byte[]) bytes;
        }
        return null;
    }

    @Override
    public String getXmlInfoById(String xmlId) {
        DynaBean dynaBean = metaService.selectOneByPk("act_ge_bytearray", xmlId);
        if (dynaBean != null) {
            Object bytes = dynaBean.get("BYTES_");
            if (bytes == null) {
                return null;
            }
            return new String((byte[]) bytes, Charsets.UTF_8);
        }
        return null;
    }

    public static boolean scale(BufferedImage read, File destImageFile, float scale) {

        try {
            //获取缩放后的宽高
            int width = (int) (read.getWidth() * scale);
            int height = (int) (read.getHeight() * scale);
            //调用缩放方法获取缩放后的图片
            Image img = read.getScaledInstance(width, height, Image.SCALE_SMOOTH);
            //创建一个新的缓存图片
            BufferedImage image = new BufferedImage(width, height, BufferedImage.SCALE_FAST);

            //获取画笔
            Graphics2D graphics = image.createGraphics();
            //将Image对象画在画布上,最后一个参数,ImageObserver:接收有关 Image 信息通知的异步更新接口,没用到直接传空
            graphics.drawImage(img, 0, 0, null);
            //一定要释放资源
            graphics.dispose();
            //使用ImageIO的write方法进行输出
            ImageIO.write(image, "png", destImageFile);
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

}
